﻿using System;
using System.Collections.Generic;
using ParserGenerator.Collections;
using ParserGenerator.GrammarConstruction;

namespace ParserGenerator.ParserConstruction
{
    [Serializable]
    public sealed class ParserAutomatonItemSet : ReadOnlySet<ParserAutomatonItem>
    {
        internal ParserAutomatonItemSet()
            : base(new HashSet<ParserAutomatonItem>())
        {
        }

        public ParserAutomatonItemSet ComputeClosure()
        {
            return ComputeClosure(false);
        }

        public ParserAutomatonItemSet ComputeClosure(bool includeCore)
        {
            ParserAutomatonItemSet closure = new ParserAutomatonItemSet();
            if (includeCore)
                closure.UnionWith(this);
            foreach (ParserAutomatonItem item in Set)
                if (item.IsGoto)
                    foreach (GrammarProduction prod in item.Symbol.AsNonterminal.Derives)
                        closure.Add(prod.FirstItem);
            return closure;
        }

        internal void Add(ParserAutomatonItem item)
        {
            if (item == null)
                throw new ArgumentNullException(nameof(item));
            Set.Add(item);
        }

        internal void UnionWith(ParserAutomatonItemSet items)
        {
            if (items == null)
                throw new ArgumentNullException(nameof(items));
            Set.UnionWith(items.Set);
        }

        public bool Equals(ParserAutomatonItemSet other)
        {
            return other != null && Set.SetEquals(other.Set);
        }

        public sealed override bool Equals(object obj)
        {
            return obj is ParserAutomatonItemSet && Equals((ParserAutomatonItemSet)obj);
        }

        public sealed override int GetHashCode()
        {
            return GetSetHashCode();
        }

        public sealed override string ToString()
        {
            return string.Join("\n", Set);
        }
    }
}
